﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using System.Windows;

namespace Rowing
{
    public class Boat
    {
        private const string disregardPath = "\\bin\\Debug";
        private const string boatImgPath = "/Images/world.jpg";
        private const int size = 2;
        private Vector3D currPos;
        private MeshGeometry3D boatMesh = null;
        private Material boatMaterial;
        public int groundSize = 20;
        //private double testSpeed = 0.2;
        public Vector3D currVelocity;
        private Vector3D currDirection;

        public Boat()
        {
            SetImage();
            InitPosList();
        }

        private void InitPosList()
        {
            currPos = new Vector3D(0, 1, 0);
            currDirection = new Vector3D(0, 0, 0.001);
            currVelocity = new Vector3D(0, 0, 0);
        }

        private void SetImage()
        {
            string filepath = Path.GetFullPath(@".");
            if (filepath.EndsWith(disregardPath))
                filepath = filepath.Replace(disregardPath, "");
            filepath += boatImgPath;
            Console.WriteLine("Image Boat File(" + Path.GetFullPath(filepath) + ") exists : " + File.Exists(filepath));
            ImageBrush boatBrush = new ImageBrush(new BitmapImage(new Uri(filepath, UriKind.Relative)));
            boatMaterial = new DiffuseMaterial(boatBrush);
        }

        
        public void SetSpeed(float leftSpeed, float rightSpeed, float direction)
        {
            currVelocity = new Vector3D(0, 0, 0);
            float speed = (leftSpeed + rightSpeed) / 2;
            leftSpeed /= 100;
            rightSpeed /= 100;
            if (currDirection.Z >= 0)
            {
                // 4사분면일 때
                if (currDirection.X >= 0)
                {
                    currDirection.X -= direction;
                    currDirection.Z += direction;
                    currVelocity.X -= rightSpeed;
                    currVelocity.Z += leftSpeed;
                }
                else
                {// 3사분면일 때
                    currDirection.X -= direction;
                    currDirection.Z -= direction;
                    currVelocity.X -= rightSpeed;
                    currVelocity.Z -= leftSpeed;
                }
            }
            else
            {
                // 2사분면일 때
                if (currDirection.X >= 0)
                {
                    currDirection.X += direction;
                    currDirection.Z -= direction;
                    currVelocity.X += rightSpeed;
                    currVelocity.Z -= leftSpeed;
                }
                else
                {// 1사분면일 때
                    currDirection.X += direction;
                    currDirection.Z += direction;
                    currVelocity.X += rightSpeed;
                    currVelocity.Z += leftSpeed;
                }
            }
            currVelocity.X += currDirection.X /1000;
            currVelocity.Z += currDirection.Z /1000;
        }

        public void SetSpeed(Vector3D speed)
        {
            currVelocity.X += speed.X;
            currVelocity.Z += speed.Z;
        }

        /*
         *  속도와 방향을 통해 현재 위치 계산
         */
        public bool CalcMoving()
        {
            currPos = new Vector3D(currPos.X + currVelocity.X, 1, currPos.Z + currVelocity.Z);
            if (currPos.X >= (float)(groundSize - 1) / 2 || currPos.X <= -(float)2 * (groundSize - 3) / 5
                || currPos.Z >= (float)(groundSize) / 2 || currPos.Z <= -(float)groundSize / 4)
                return false;
            return true;
        }

        public void Display(Model3DGroup boatModel)
        {
            // Make the mesh if we must.
            if (boatMesh == null)
            {
                boatMesh = new MeshGeometry3D();
                GeometryModel3D newModel = new GeometryModel3D(boatMesh, boatMaterial);
                boatModel.Children.Add(newModel);
            }

            double radius = 0.5;
            int num_phi = 20;
            int num_theta = 30;
            double dphi = Math.PI / num_phi;
            double dtheta = 2 * Math.PI / num_theta;

            // Remember the first point.
            boatMesh.Positions.Clear();
            int pt0 = boatMesh.Positions.Count;

            // Make the points.
            double phi1 = Math.PI / 2;
            bool isWillbeFrozen = false;
            for (int p = 0; p <= num_phi; p++)
            {
                double r1 = radius * Math.Cos(phi1);
                double y1 = radius * Math.Sin(phi1);

                double theta = 0;
                for (int t = 0; t <= num_theta; t++)
                {
                    boatMesh.Positions.Add(new Point3D(
                        currPos.X + r1 * Math.Cos(theta), currPos.Y + y1, currPos.Z + -r1 * Math.Sin(theta)));
                    if (!boatMesh.TextureCoordinates.IsFrozen)
                    {
                        boatMesh.TextureCoordinates.Add(new Point(
                        (double)t / num_theta, (double)p / num_phi));
                        isWillbeFrozen = true;
                    }
                    theta += dtheta;
                }
                phi1 -= dphi;
            }
            if(isWillbeFrozen)
                boatMesh.TextureCoordinates.Freeze();

            // Make the triangles.
            if (!boatMesh.TriangleIndices.IsFrozen)
            {
                int i1, i2, i3, i4;
                for (int p = 0; p <= num_phi - 1; p++)
                {
                    i1 = p * (num_theta + 1);
                    i2 = i1 + (num_theta + 1);
                    for (int t = 0; t <= num_theta - 1; t++)
                    {
                        i3 = i1 + 1;
                        i4 = i2 + 1;
                        boatMesh.TriangleIndices.Add(pt0 + i1);
                        boatMesh.TriangleIndices.Add(pt0 + i2);
                        boatMesh.TriangleIndices.Add(pt0 + i4);

                        boatMesh.TriangleIndices.Add(pt0 + i1);
                        boatMesh.TriangleIndices.Add(pt0 + i4);
                        boatMesh.TriangleIndices.Add(pt0 + i3);
                        i1 += 1;
                        i2 += 1;
                    }
                }
                boatMesh.TriangleIndices.Freeze();
            }
        }

        public void Destroy()
        {
            currPos = new Vector3D(0, 1, 0);
            currDirection = new Vector3D(0, 0, 0);
            currVelocity = new Vector3D(0, 0, 0);
        }
    }
}
